package jp.dodododo.aop.interceptors;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import jp.dodododo.aop.annotation.Enhance;
import jp.dodododo.janerics.GenericsMethodUtil;

import org.aopalliance.intercept.ConstructorInvocation;
import org.aopalliance.intercept.Interceptor;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

@Enhance(false)
public class InterceptorChain implements MethodInterceptor, ConstructorInterceptor {

	private List<Interceptor> interceptors = new ArrayList<Interceptor>();

	private AccessibleObject staticPart;

	private boolean isDefaultPointcut;

	public InterceptorChain(AccessibleObject staticPart, boolean isDefaultPointcut) {
		this.isDefaultPointcut = isDefaultPointcut;
	}

	public void add(Object interceptor) {
		if (interceptor instanceof Interceptor) {
			add((Interceptor) interceptor);
		} else {
			add(new JeeSpecInterceptorWrapper(interceptor));
		}
	}

	public void add(Interceptor interceptor) {
		if (isDefaultPointcut == true) {
			if (staticPart instanceof Constructor<?>) {
				return;
			} else if (staticPart instanceof Method) {
				if (GenericsMethodUtil.isImplMethod((Method) staticPart) == false) {
					return;
				}
			}
		}
		interceptors.add(interceptor);
	}

	public Object invoke(MethodInvocation invocation) throws Throwable {
		MethodInvocation nestInvocation = new NestedMethodInvocation(invocation, interceptors);
		return nestInvocation.proceed();
	}

	public Object construct(ConstructorInvocation invocation) throws Throwable {
		ConstructorInvocation nestInvocation = new NestedConstructorInvocation(invocation, interceptors);
		return nestInvocation.proceed();
	}
}
